package com.hummingbird.portal.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hummingbird.portal.dto.RegisterDTO;
import com.hummingbird.portal.exception.ServiceException;
import com.hummingbird.portal.mapper.ClassroomMapper;
import com.hummingbird.portal.mapper.UserCollectMapper;
import com.hummingbird.portal.mapper.UserRoleMapper;
import com.hummingbird.portal.pojo.*;
import com.hummingbird.portal.mapper.UserMapper;
import com.hummingbird.portal.service.IQuestionService;
import com.hummingbird.portal.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hummingbird.portal.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author -1E18
 * @since 2024-09-22
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private UserMapper userMapper;

    private List<User> masters = new CopyOnWriteArrayList<>();

    private Map<String, User> masterMap = new ConcurrentHashMap<>();

    private Timer timer = new Timer();
    {
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                masters.clear();
                masterMap.clear();
                log.debug("缓存已清空");
            }
        }, 1000 * 60 * 30, 1000 * 60 * 30); //  1000毫秒 * 60 = 1分钟 1分钟 * 30 = 30分钟
        // 没有固定时间 根据运行情况设置
    }

    @Override
    public UserDetails getUserDetails(String username) {
        User user = userMapper.findUserByUsername(username);
        if (user == null) {
            return null;
        }

        List<Permission> userPermissionsById = userMapper.findUserPermissionsById(user.getId());
        String[] auth = new String[userPermissionsById.size()];

        int idx = 0;
        for (Permission permission : userPermissionsById) {
            auth[idx ++ ] = permission.getName();   // question.create / index.html
        }

        List<Role> roles = userMapper.findUserRoleById(user.getId());
        auth = Arrays.copyOf(auth, auth.length + roles.size());
        for (Role role : roles) {
            auth[idx ++ ] = role.getName();
        }

        UserDetails userDetails = org.springframework.security.core.userdetails
                .User.builder().username(user.getUsername()).password(user.getPassword())
                .authorities(auth).accountLocked(user.getLocked() == 1).disabled(user.getEnabled() == 0)
                .build();
        return userDetails;
    }

    @Autowired
    private ClassroomMapper classroomMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Override
    @Transactional  // 保证事务 同时成功 或 同时失败
    public void registerStudent(RegisterDTO registerDTO) {
        QueryWrapper<Classroom> queryWrapper = new QueryWrapper<>();    // sql 简单查询
        // select * from classroom where invite_code = registerDTO.getInvitecode()
        queryWrapper.eq("invite_code", registerDTO.getInviteCode());

        Classroom classroom = classroomMapper.selectOne(queryWrapper);
        if (classroom == null) {
            throw ServiceException.unprocesabelEntity("邀请码错误");
        }

        User userByUsername = userMapper.findUserByUsername(registerDTO.getPhone());
        if (userByUsername != null) {
            throw ServiceException.unprocesabelEntity("手机号已经被注册");
        }

        User user = new User();
        user.setUsername(registerDTO.getPhone());
        user.setNickname(registerDTO.getNickname());
        user.setClassroomId(classroom.getId());

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String password = "{bcrypt}" + encoder.encode(registerDTO.getPassword());
        user.setPassword(password);

        user.setCreatetime(LocalDateTime.now());
        user.setType(0);
        user.setLocked(0);
        user.setEnabled(1);

        int num = userMapper.insert(user);
        if (num != 1) {
            throw ServiceException.busy();
        }
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(2);

        num = userRoleMapper.insert(userRole);
        if (num != 1) {
            throw ServiceException.busy();
        }
    }

    @Override
    public List<User> getMasters() {
        if (masters.isEmpty()) {
            synchronized (masters) {
                if (masters.isEmpty()) {
                    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("type", 1); // 牢师
                    List<User> teachers = userMapper.selectList(queryWrapper);
                    masters.addAll(teachers);

                    for (User teacher : teachers) {
                        masterMap.put(teacher.getNickname(), teacher);
                    }
                    // modCount: 若在遍历时进行修改 modCount冲突
                    for (User teacher : teachers) {
                        teacher.setPassword("");
                    }
                }
            }
            return masters;
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type", 1); // 牢师
        List<User> teachers = userMapper.selectList(queryWrapper);
        return teachers;
    }

    @Override
    public Map<String, User> getMastersMap() {
        if (masters.isEmpty()) {
            getMasters();
        }
        return masterMap;
    }

    @Resource
    private UserCollectMapper userCollectMapper;

    @Override
    public int countCollectionsByUserId(Integer id) {
        QueryWrapper<UserCollect> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_Id", id);
        Integer cnt = userCollectMapper.selectCount(queryWrapper);
        return cnt;
    }

    @Resource
    private IQuestionService questionService;

    @Override
    public UserVO getCurrentUserVO(String username) {
        UserVO userVO = userMapper.findUserVOByUsername(username);
        userVO.setCollections(this.countCollectionsByUserId(userVO.getId()));
        userVO.setQuestions(questionService.countQuestionByUserId(userVO.getId()));
        return userVO;
    }
}
